
#include <BScript>
#include "IClassArray.h"

using namespace BWE;

ClassArray::ClassArray() : BClass("array<T>")
{
	this->insertMethod("array<T>()", &ClassArray::create);
	this->insertMethod("array<T>(int)", &ClassArray::create_size);
	this->insertMethod("array<T>(const T&, int)", &ClassArray::create_value_size);
	this->insertMethod("array<T>(const array<T>&)", &ClassArray::create_array);
	this->insertMethod("array<T>(const array<T>&, int, int)", &ClassArray::create_array_pos_size);
	this->insertMethod("~array<T>()", &ClassArray::release);

	this->insertMethod("bool empty() const", &ClassArray::empty);
	this->insertMethod("int size() const", &ClassArray::size);
	this->insertMethod("int capacity() const", &ClassArray::capacity);
	this->insertMethod("void reset()", &ClassArray::reset);
	this->insertMethod("void clear()", &ClassArray::clear);

	this->insertMethod("bool resize(int)", &ClassArray::resize);
	this->insertMethod("bool reserve(int)", &ClassArray::reserve);
	this->insertMethod("bool check(int) const", &ClassArray::check);

	this->insertMethod("bool set(int, const T&)", &ClassArray::set_pos_value);
	this->insertMethod("bool set(int, const array<T>&)", &ClassArray::set_pos_array);

	this->insertMethod("bool fill(const T&)", &ClassArray::fill_value);
	this->insertMethod("bool fill(const T&, int, int)", &ClassArray::fill_value_pos_size);

	this->insertMethod("int find(const T&, int) const", &ClassArray::find);
	this->insertMethod("int rfind(const T&, int) const", &ClassArray::rfind);

	this->insertMethod("int count(const T&) const", &ClassArray::count);
	this->insertMethod("int contain(const T&) const", &ClassArray::contain);
	this->insertMethod("int replace(const T&, const T&)", &ClassArray::replace);

	this->insertMethod("bool move(int, int)", &ClassArray::move);
	this->insertMethod("bool swap(int, int)", &ClassArray::swap);

	this->insertMethod("bool reverse()", &ClassArray::reverse);

	this->insertMethod("bool raise(const T&)", &ClassArray::raise);
	this->insertMethod("bool lower(const T&)", &ClassArray::lower);

	this->insertMethod("T& first()", &ClassArray::first);
	this->insertMethod("const T& first() const", &ClassArray::first_const);

	this->insertMethod("T& last()", &ClassArray::last);
	this->insertMethod("const T& last() const", &ClassArray::last_const);

	this->insertMethod("T& middle()", &ClassArray::middle);
	this->insertMethod("const T& middle() const", &ClassArray::middle_const);

	this->insertMethod("T& at(int)", &ClassArray::at);
	this->insertMethod("const T& at(int) const", &ClassArray::at_const);

	this->insertMethod("T& def()", &ClassArray::def_const);
	this->insertMethod("const T& def() const", &ClassArray::def_const);

	this->insertMethod("T& append()", &ClassArray::append);
	this->insertMethod("bool append(T)", &ClassArray::append_value);
	this->insertMethod("bool append(const T&, int)", &ClassArray::append_value_size);
	this->insertMethod("bool append(const array<T>&, int, int)", &ClassArray::append_array_pos_size);

	this->insertMethod("bool prepend()", &ClassArray::prepend);
	this->insertMethod("bool prepend(T)", &ClassArray::prepend_value);
	this->insertMethod("bool prepend(const T&, int)", &ClassArray::prepend_value_size);
	this->insertMethod("bool prepend(const array<T>&, int, int)", &ClassArray::prepend_array_pos_size);

	this->insertMethod("T& insert(int)", &ClassArray::insert_pos_value);
	this->insertMethod("bool insert(int, const T&, int)", &ClassArray::insert_pos_value_size);
	this->insertMethod("bool insert(int, const array<T>&, int, int)", &ClassArray::insert_pos_array_first_size);

	this->insertMethod("bool remove(int, int)", &ClassArray::remove_pos_size);
	this->insertMethod("bool remove(const T&)", &ClassArray::remove_value);
	this->insertMethod("bool remove(const array<T>&)", &ClassArray::remove_array);

	this->insertMethod("T& ()(int)", &ClassArray::operator_brackets);
	this->insertMethod("T& [](int)", &ClassArray::operator_square_brackets);

	this->insertMethod("const array<T>& =(const array<T>&)", &ClassArray::operator_equal_array);

	this->insertMethod("array<T> +(const T&)", &ClassArray::operator_plus_value);
	this->insertMethod("array<T> +(const array<T>&)", &ClassArray::operator_plus_array);

	this->insertMethod("void +=(const T&)", &ClassArray::operator_plus_equal_value);
	this->insertMethod("void -=(const T&)", &ClassArray::operator_minus_equal_value);

	this->insertMethod("array<T>& <<(const T&)", &ClassArray::operator_append_value);
	this->insertMethod("array<T>& <<(const array<T>&)", &ClassArray::operator_append_array);

	this->insertMethod("bool ==(const array<T>&) const", &ClassArray::operator_equal);
	this->insertMethod("bool !=(const array<T>&) const", &ClassArray::operator_unequal);

}

BClass* ClassArray::clone() const
{
	ClassArray* cls = new ClassArray();
	cls->copy(this);
	return cls;
}

void ClassArray::create(int argc, BValue* argv)
{
	this->setAsset(new BValueArray());
}
void ClassArray::create_size(int argc, BValue* argv)
{
	int size = argv[1];
	BValueArray* array = new BValueArray(size);
	const BString& type = this->tempTypes().first();
	BScript* script = this->script();
	for (int i = 0; i < array->size(); i++)
	{
		script->create(type, array->at(i));
	}
	this->setAsset(array);
}
void ClassArray::create_value_size(int argc, BValue* argv)
{
	const BValue& value = argv[1];
	int size = argv[2];
	BValueArray* array = new BValueArray(size);
	const BString& type = this->tempTypes().first();
	for (int i = 0; i < array->size(); i++)
	{
		this->script()->create(type, array->at(i), value);
	}
	this->setAsset(array);
}
void ClassArray::create_array(int argc, BValue* argv)
{
	BValueArray* array = new BValueArray();
	if (ClassArray* cls = argv[1])
	{
		const BValueArray& other = cls->asset();
		array->resize(other.size());
		const BString& type = this->tempTypes().first();
		for (int i = 0; i < array->size(); i++)
		{
			this->script()->create(type, array->at(i), other.at(i));
		}
	}
	this->setAsset(array);
}
void ClassArray::create_array_pos_size(int argc, BValue* argv)
{
	BValueArray* array = new BValueArray();
	if (ClassArray* cls = argv[1])
	{
		const BValueArray& other = cls->asset();
		int pos = argv[2];
		int size = argv[3];
		array->resize(size);
		const BString& type = this->tempTypes().first();
		for (int i = 0; i < size; i++)
		{
			this->script()->create(type, array->at(i), other.at(pos + i));
		}
	}
	this->setAsset(array);
}
void ClassArray::release(int argc, BValue* argv)
{
	BValueArray& array = this->asset();
	array.clear();
}

void ClassArray::empty(int argc, BValue* argv)
{
	const BValueArray& array = this->asset();
	argv[0] = array.empty();
}
void ClassArray::size(int argc, BValue* argv)
{
	const BValueArray& array = this->asset();
	argv[0] = array.size();
}
void ClassArray::capacity(int argc, BValue* argv)
{
	const BValueArray& array = this->asset();
	argv[0] = array.capacity();
}
void ClassArray::reset(int argc, BValue* argv)
{
	BValueArray& array = this->asset();
	array.reset();
}
void ClassArray::clear(int argc, BValue* argv)
{
	BValueArray& array = this->asset();
	array.clear();
}

void ClassArray::resize(int argc, BValue* argv)
{
	BValueArray& array = this->asset();
	int size = argv[1];
	array.resize(size);
}
void ClassArray::reserve(int argc, BValue* argv)
{
	BValueArray& array = this->asset();
	int size = argv[1];
	array.reserve(size);
}
void ClassArray::check(int argc, BValue* argv)
{
	const BValueArray& array = this->asset();
	int index = argv[1];
	argv[0] = array.check(index);
}

void ClassArray::set_pos_value(int argc, BValue* argv)
{
	BValueArray& array = this->asset();
	int pos = argv[1];
	const BValue& value = argv[2].refer();
	array.set(pos, value);
}
void ClassArray::set_pos_array(int argc, BValue* argv)
{
	BValueArray& array = this->asset();
	int pos = argv[1];
	const BValueArray& other = argv[2].refer();
	array.set(pos, other);
}

void ClassArray::fill_value(int argc, BValue* argv)
{
	BValueArray& array = this->asset();
	const BValue& value = argv[1].refer();
	array.fill(value);
}
void ClassArray::fill_value_pos_size(int argc, BValue* argv)
{
	BValueArray& array = this->asset();
	const BValue& value = argv[1].refer();
	int pos = argv[2];
	int size = argv[3];
	array.fill(value, pos, size);
}

void ClassArray::find(int argc, BValue* argv)
{
	const BValueArray& array = this->asset();
	const BValue& value = argv[0].refer();
	int pos = argv[2];
	argv[0] = array.find(value, pos);
}
void ClassArray::rfind(int argc, BValue* argv)
{
	const BValueArray& array = this->asset();
	const BValue& value = argv[1].refer();
	int pos = argv[2];
}

void ClassArray::count(int argc, BValue* argv)
{
	const BValueArray& array = this->asset();
	const BValue& value = argv[1].refer();
	argv[0] = array.count(value);
}
void ClassArray::contain(int argc, BValue* argv)
{
	const BValueArray& array = this->asset();
	const BValue& value = argv[1].refer();
	bool res = array.contain(value);
	argv[0] = res;
}
void ClassArray::replace(int argc, BValue* argv)
{
	BValueArray& array = this->asset();
	const BValue& oldValue = argv[1].refer();
	const BValue& newValue = argv[2].refer();
	int size = array.replace(oldValue, newValue);
	argv[0] = size;
}

void ClassArray::move(int argc, BValue* argv)
{
	BValueArray& array = this->asset();
	int index = argv[1];
	int dest = argv[2];
	bool res = array.move(index, dest);
	argv[0] = res;
}
void ClassArray::swap(int argc, BValue* argv)
{
	BValueArray& array = this->asset();
	int index0 = argv[1];
	int index1 = argv[2];
	bool res = array.swap(index0, index1);
	argv[0] = res;
}

void ClassArray::reverse(int argc, BValue* argv)
{
	BValueArray& array = this->asset();
	array.reverse();
}

void ClassArray::raise(int argc, BValue* argv)
{
	BValueArray& array = this->asset();
	const BValue& value = argv[1].refer();
	array.raise(value);
}
void ClassArray::lower(int argc, BValue* argv)
{
	BValueArray& array = this->asset();
	const BValue& value = argv[1].refer();
	array.lower(value);
}

void ClassArray::first(int argc, BValue* argv)
{
	const BValueArray& array = this->asset();
	const BValue& value = array.first();
	argv[0] = value;
}
void ClassArray::first_const(int argc, BValue* argv)
{
	const BValueArray& array = this->asset();
	const BValue& value = array.first();
	argv[0] = value;
}

void ClassArray::last(int argc, BValue* argv)
{
	const BValueArray& array = this->asset();
	const BValue& value = array.last();
	argv[0] = value;
}
void ClassArray::last_const(int argc, BValue* argv)
{
	const BValueArray& array = this->asset();
	const BValue& value = array.last();
	argv[0] = value;
}

void ClassArray::middle(int argc, BValue* argv)
{
	const BValueArray& array = this->asset();
	const BValue& value = array.middle();
	argv[0] = value;
}
void ClassArray::middle_const(int argc, BValue* argv)
{
	const BValueArray& array = this->asset();
	const BValue& value = array.middle();
	argv[0] = value;
}

void ClassArray::at(int argc, BValue* argv)
{
	const BValueArray& array = this->asset();
	int index = argv[1];
	const BValue& value = array.at(index);
	argv[0] = value;
}
void ClassArray::at_const(int argc, BValue* argv)
{
	const BValueArray& array = this->asset();
	int index = argv[1];
	const BValue& value = array.at(index);
	argv[0] = value;
}

void ClassArray::def(int argc, BValue* argv)
{
	const BValueArray& array = this->asset();
	const BValue& value = array.def();
	argv[0] = value;
}
void ClassArray::def_const(int argc, BValue* argv)
{
	const BValueArray& array = this->asset();
	const BValue& value = array.def();
	argv[0] = value;
}

void ClassArray::append(int argc, BValue* argv)
{
	BValueArray& array = this->asset();
	const BString& type = this->tempTypes().first();
	BValue& value = array.append();
	this->script()->create(type, value);
	argv[0] = value;
}
void ClassArray::append_value(int argc, BValue* argv)
{
	BValueArray& array = this->asset();
	BValue& value = array.append();
	if (BScript* script = this->script())
	{
		const BString& type = this->tempTypes().first();
		const BValue& param = argv[1].refer();
		argv[0] = script->create(type, value, param);
	}
}
void ClassArray::append_value_size(int argc, BValue* argv)
{
	BValueArray& array = this->asset();
	if (BScript* script = this->script())
	{
		const BString& type = this->tempTypes().first();
		const BValue& param = argv[1].refer();
		int size = argv[2];
		for (int i = 0; i < size; i++)
		{
			BValue& value = array.append();
			script->create(type, value, param);
		}
		argv[0] = true;
	}
}
void ClassArray::append_array_pos_size(int argc, BValue* argv)
{
	BValueArray& array = this->asset();
	if (ClassArray* cls = argv[1])
	{
		const BValueArray& other = cls->asset();
		int pos = argv[2];
		int size = argv[3];
		argv[0] = array.append(other, pos, size);
	}
}

void ClassArray::prepend(int argc, BValue* argv)
{
	BValueArray& array = this->asset();
	const BString& type = this->tempTypes().first();
	BValue& value = array.prepend();
	this->script()->create(type, value);
	argv[0] = value;
}
void ClassArray::prepend_value(int argc, BValue* argv)
{
	BValueArray& array = this->asset();
	BValue& value = array.prepend();
	if (BScript* script = this->script())
	{
		const BString& type = this->tempTypes().first();
		const BValue& param = argv[1].refer();
		argv[0] = script->create(type, value, param);
	}
	argv[0] = value;
}
void ClassArray::prepend_value_size(int argc, BValue* argv)
{
	BValueArray& array = this->asset();
	if (BScript* script = this->script())
	{
		const BString& type = this->tempTypes().first();
		const BValue& param = argv[1].refer();
		int size = argv[2];
		for (int i = 0; i < size; i++)
		{
			BValue& value = array.prepend();
			script->create(type, value, param);
		}
		argv[0] = true;
	}
}
void ClassArray::prepend_array_pos_size(int argc, BValue* argv)
{
	BValueArray& array = this->asset();
	if (ClassArray* cls = argv[1])
	{
		const BValueArray& other = cls->asset();
		int pos = argv[2];
		int size = argv[3];
		argv[0] = array.prepend(other, pos, size);
	}
}

void ClassArray::insert_pos_value(int argc, BValue* argv)
{
	BValueArray& array = this->asset();
	int pos = argv[1];
	const BValue& value = array.insert(pos);
	argv[0] = value;
}
void ClassArray::insert_pos_value_size(int argc, BValue* argv)
{
	BValueArray& array = this->asset();
	int pos = argv[1];
	const BValue& value = argv[2];
	int size = argv[3];
	bool res = array.insert(pos, value, size);
	argv[0] = res;
}
void ClassArray::insert_pos_array_first_size(int argc, BValue* argv)
{
	BValueArray& array = this->asset();
	int pos = argv[1];
	const BValueArray& other = argv[2];
	int first = argv[3];
	int size = argv[4];
	bool res = array.insert(pos, other, first, size);
	argv[0] = res;
}

void ClassArray::remove_pos_size(int argc, BValue* argv)
{
	BValueArray& array = this->asset();
	int pos = argv[1];
	int size = argv[2];
	bool res = array.remove(pos, size);
	argv[0] = res;
}
void ClassArray::remove_value(int argc, BValue* argv)
{
	BValueArray& array = this->asset();
	const BValue& value = argv[1].refer();
	bool res = array.remove(value);
	argv[0] = res;
}
void ClassArray::remove_array(int argc, BValue* argv)
{
	BValueArray& array = this->asset();
	argv[0] = false;
	if (ClassArray* cls = argv[1])
	{
		const BValueArray& other = cls->asset();
		argv[0] = array.remove(other);
	}
}

void ClassArray::operator_brackets(int argc, BValue* argv)
{
	const BValueArray& array = this->asset();
	int index = argv[1];
	const BValue& value = array(index);
	argv[0] = value;
}
void ClassArray::operator_square_brackets(int argc, BValue* argv)
{
	const BValueArray& array = this->asset();
	int index = argv[1];
	const BValue& value = array(index);
	argv[0] = value;
}
void ClassArray::operator_equal_array(int argc, BValue* argv)
{
	BValueArray& array = this->asset();
	if (ClassArray* cls = argv[1])
	{
		const BValueArray& other = cls->asset();
		array = other;
	}
}
void ClassArray::operator_plus_value(int argc, BValue* argv)
{
	const BValueArray& array = this->asset();
	const BValue& value = argv[1];
	argv[0] = array + value;
}
void ClassArray::operator_plus_array(int argc, BValue* argv)
{
	const BValueArray& array = this->asset();
	if (ClassArray* cls = argv[1])
	{
		const BValueArray& other = cls->asset();
		this->script()->create(this->name(), argv[0]);
		ClassArray* result = argv[0];
		BValueArray& resultArray = result->asset();
		resultArray = array + other;
	}
}
void ClassArray::operator_plus_equal_value(int argc, BValue* argv)
{
	BValueArray& array = this->asset();
	const BValue& value = argv[1];
	array += value;
}
void ClassArray::operator_minus_equal_value(int argc, BValue* argv)
{
	BValueArray& array = this->asset();
	const BValue& value = argv[1];
	array -= value;
}
void ClassArray::operator_append_value(int argc, BValue* argv)
{
	BValueArray& array = this->asset();
	const BValue& value = argv[1];
	array << value;
}
void ClassArray::operator_append_array(int argc, BValue* argv)
{
	BValueArray& array = this->asset();
	if (ClassArray* cls = argv[1])
	{
		const BValueArray& other = cls->asset();
		array << other;
	}
}
void ClassArray::operator_equal(int argc, BValue* argv)
{
	const BValueArray& array = this->asset();
	if (ClassArray* cls = argv[1])
	{
		const BValueArray& other = cls->asset();
		argv[0] = (array == other);
	}
}
void ClassArray::operator_unequal(int argc, BValue* argv)
{
	const BValueArray& array = this->asset();
	if (ClassArray* cls = argv[1])
	{
		const BValueArray& other = cls->asset();
		argv[0] = (array != other);
	}
}
